/*
 * Copyright (c) 2011 Norbert Kopcsek
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package org.modulr.bundle {

	import flash.events.EventDispatcher;

	import mx.collections.ArrayList;
	import mx.collections.IList;
	import mx.modules.IModuleInfo;
	import mx.modules.ModuleManager;

	[DefaultProperty( "source" )]
	/**
	 * An installed bundle in the Framework.
	 *
	 * A Bundle object is the access point to define the life cycle of an installed bundle.
	 * Each bundle installed in the framework will have an associated Bundle object.
	 *
	 * A bundle can be in one of seven states:
	 *
	 * - INSTALLED
	 * - QUEUED
	 * - LOADING
	 * - STARTING
	 * - STOPPING
	 * - ACTIVE
	 * - ERROR
	 *
	 * The Framework is the only entity that is allowed to create Bundle objects, and these objects are only valid within the Framework that created them.
	 *
	 * @see org.modulr.bundle.BundleState
	 * @see org.modulr.bundle.BundleContext
	 * @see org.modulr.bundle.IBundleContext
	 * @see org.modulr.framework.Framework
	 *
	 * @author Norbert Kopcsek
	 */
    // TODO Enforce that only the framework can create bundles. One way would be a namespace
	public class Bundle extends EventDispatcher {


		//------------------------------------------------------------------------------
		//
		//   Constructor 
		//
		//------------------------------------------------------------------------------

		public function Bundle( bundleId:String = null, url:String = null, activatorName:String = null, mandatory:Boolean = false, rsl:Boolean = false, version:String = "1.0" ) {
			this.bundleId = bundleId;
			this.url = url;
			this.activatorName = activatorName;
			this.mandatory = mandatory;
			this.isRsl = rsl;
			this.version = version;
			this.state = BundleState.INSTALLED;
		}


		//------------------------------------------------------------------------------
		//
		//   Properties (Getter/Setter) 
		//
		//------------------------------------------------------------------------------

		//--------------------------------------
		// bundleId 
		//--------------------------------------

		/**
		 * The id of the bundle.
		 */
		public function get bundleId():String {
			return _bundleId;
		}

		public function set bundleId( value:String ):void {
			_bundleId = value;
		}

		//--------------------------------------
		// url 
		//--------------------------------------

		/**
		 * The url of the bundle.
		 */
		public function get url():String {
			return _url;
		}

		public function set url( value:String ):void {
			_url = value;
		}

		//--------------------------------------
		// context 
		//--------------------------------------

		/**
		 * The context of the bundle.
		 */
		public function get context():IBundleContext {
			return _context;
		}

		public function set context( value:IBundleContext ):void {
			_context = value;
		}

		//--------------------------------------
		// state 
		//--------------------------------------

		[Bindable]
		/**
		 * A bundle can be in one of seven states:
		 * - INSTALLED
		 * - QUEUED
		 * - LOADING
		 * - STARTING
		 * - STOPPING
		 * - ACTIVE
		 * - ERROR
		 */
		public function get state():String {
			return _state;
		}

		public function set state( value:String ):void {
			_state = value;
		}

		//--------------------------------------
		// activator 
		//--------------------------------------

		/**
		 * The activator of the bundle.
		 */
		public function get activator():IBundleActivator {
			return _activator;
		}

		public function set activator( value:IBundleActivator ):void {
			_activator = value;
		}

		//--------------------------------------
		// activatorName 
		//--------------------------------------

		/**
		 * The activatorName of the bundle.
		 */
		public function get activatorName():String {
			return _activatorName;
		}

		public function set activatorName( value:String ):void {
			if ( value != null && value.length == 0 ) {
				_activatorName = null;
			}
			_activatorName = value;
		}

		//--------------------------------------
		// moduleInfo 
		//--------------------------------------

		/**
		 * The moduleInfo of the bundle.
		 */
		public function get moduleInfo():IModuleInfo {
			if ( _moduleInfo == null && !isRsl ) {
				_moduleInfo = ModuleManager.getModule( url );
			}
			return _moduleInfo;
		}

		//--------------------------------------
		// mandatory 
		//--------------------------------------

		/**
		 * Defines whether the bundle has to be loaded at startup or not.
		 */
		public function get mandatory():Boolean {
			return _mandatory;
		}

		public function set mandatory( value:Boolean ):void {
			_mandatory = value;
		}

		//--------------------------------------
		// isRsl 
		//--------------------------------------

		/**
		 * The isRsl of the bundle.
		 */
		public function get isRsl():Boolean {
			return _isRsl;
		}

		public function set isRsl( value:Boolean ):void {
			_isRsl = value;
		}

		//--------------------------------------
		// version 
		//--------------------------------------

		/**
		 * The version of the bundle.
		 */
		public function get version():String {
			return _version;
		}

		public function set version( value:String ):void {
			_version = value;
		}

		//--------------------------------------
		// requiredBundles 
		//--------------------------------------

		/**
		 * The required bundles of the bundle.
		 */
		public function get requiredBundles():Array {
			return _requiredBundles;
		}

		//--------------------------------------
		// requiredByBundles 
		//--------------------------------------

		/**
		 * The bundles requiring this bundle.
		 */
		public function get requiredByBundles():Array {
			return _requiredByBundles;
		}

		//--------------------------------------
		// source 
		//--------------------------------------

		public function set source( value:Array ):void {
			for each ( var object:Object in value ) {
				if ( object is RequiredBundle ) {
					_requiredBundles.push( object );
				}
			}
		}


		//------------------------------------------------------------------------------
		//
		//   Protected fields 
		//
		//------------------------------------------------------------------------------

		/**
		 * @private
		 */
		protected var _bundleId:String;

		/**
		 * @private
		 */
		protected var _url:String;

		/**
		 * @private
		 */
		protected var _context:IBundleContext;

		/**
		 * @private
		 */
		protected var _state:String;

		/**
		 * @private
		 */
		protected var _activator:IBundleActivator;

		/**
		 * @private
		 */
		protected var _activatorName:String;

		/**
		 * @private
		 */
		protected var _moduleInfo:IModuleInfo;

		/**
		 * @private
		 */
		protected var _mandatory:Boolean;

		/**
		 * @private
		 */
		protected var _isRsl:Boolean;

		/**
		 * @private
		 */
		protected var _version:String;

		/**
		 * @private
		 */
		protected var _requiredBundles:Array = [];

		/**
		 * @private
		 */
		protected var _requiredByBundles:Array = [];


		//------------------------------------------------------------------------------
		//
		//   Protected methods 
		//
		//------------------------------------------------------------------------------

		/**
		 * @private
		 */
		internal function clearModuleInfo():void {
			_moduleInfo = null;
		}
	}
}

